//-------------------------------------------------------------------------------------------------
// Copyright (c) Bradford W. Mott and Flare Contributors
// North Carolina State University, Department of Computer Science
// The IntelliMedia Group
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//-------------------------------------------------------------------------------------------------

using System;
using UnityEngine;

namespace Flare.Display
{
    internal class LineStyle
    {
        public float width {get; set;}
        public uint color {get; set;}
        public float radius {get; set;}
        public Texture2D filter {get; set;}

        private int numSamples = 32;

        public LineStyle(uint c, float w, float r)
        {
            color = c;
            radius = r;
            width = w;
            filter = BoxFilter(width, radius);
        }

        private Texture2D BoxFilter(float w, float r)
        {
            float filter_scale;
            // The filter scale is the scaled distance of one in pixels.
            if (w > 2.0f * r)
            {
                filter_scale = (2.0f * r);
            }
            else
            {
                filter_scale = (r + w / 2.0f);
            }
            float stepSize = filter_scale / numSamples;

            // Calculate the scaled length of the halfWidth and radius.
            float hw = w / 2.0f;
            int scaledW = (int)Mathf.Ceil(hw / stepSize);
            int scaledR = (int)Mathf.Ceil(r / stepSize);

            // The filter, then, should extend to rad in either direction
            int fLength = scaledR + scaledR + 1;
            float filter = 1.0f / fLength;

            // Set up the original texture. Intensity is 1 within
            // the wide line and 0 outside of it (with the halfLine as calculated)
            // The original texture is composed of the entire wide line (halfLine * 2 spaces)
            // plus the remaining filter spaces to be filtered.
            Texture2D original = new Texture2D((2 * scaledW) + fLength, 1);
            for (int i = 0; i < (2 * scaledW); i++)
            {
                original.SetPixel(i, 0, new Color(1.0f, 1.0f, 1.0f, 1.0f));
            }
            for (int i = (2 * scaledW); i < original.width; i++)
            {
                original.SetPixel(i, 0, new Color(1.0f, 1.0f, 1.0f, 0.0f));
            }
            original.Apply();

            // Set up the new texture, to contain the filered intensity at each of the sample points
            // from the center of the line to a distance w/2 + r away from it.
            Texture2D sampler = new Texture2D(numSamples, 1, TextureFormat.Alpha8, false);

            // Apply filter, starting with the center of the filter placed on the center of the line
            int sIndex = 0;
            int start = (2 * scaledW) + scaledR;
            for (int i = start; i > start - numSamples; i--)
            {
                float filtered = 0.0f;

                for (int index = scaledR * -1; index <= scaledR; index++)
                {
                    float x = original.GetPixel (i + index, 0).a;
                    x = filter * x;
                    filtered = filtered + x;
                }

                sampler.SetPixel (sIndex, 0, new Color(1.0f, 1.0f, 1.0f, filtered));
                sIndex++;
            }
            sampler.SetPixel (0, 0, new Color(1, 1, 1, 0));
            sampler.Apply();
            sampler.filterMode = FilterMode.Bilinear;
            sampler.wrapMode = TextureWrapMode.Clamp;

            // Update the material
            return sampler;
        }

        public override string ToString()
        {
             return string.Format("(color=0x{0:x6} width={1})", this.color, this.width);
        }
    }
}

